package com.zhentao.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhentao.common.admin.utils.AdminUserPermissionUtils;
import com.zhentao.model.common.dtos.PermissionResult;
import com.zhentao.mapper.ChargeStationInfoMapper;
import com.zhentao.model.common.dtos.ResponseResult;
import com.zhentao.model.common.enums.AppHttpCodeEnum;
import com.zhentao.model.pojo.core.ChargeStationComment;
import com.zhentao.model.pojo.core.ChargeStationDedicated;
import com.zhentao.model.pojo.core.ChargeStationGun;
import com.zhentao.model.pojo.core.ChargeStationInfo;
import com.zhentao.model.pojo.core.dto.ChargeStationInfoDto;
import com.zhentao.model.pojo.core.param.ChargeStationInfoParam;
import com.zhentao.model.pojo.core.vo.ChargeMyStationInfoVo;
import com.zhentao.model.pojo.core.vo.ChargesStationInfoVo;
import com.zhentao.service.ChargeStationCommentService;
import com.zhentao.service.ChargeStationDedicatedService;
import com.zhentao.service.ChargeStationGunService;
import com.zhentao.service.ChargeStationInfoService;
import com.zhentao.mapper.ChargeStationInfoMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static com.zhentao.common.admin.enums.AdminPermsEnum.*;
import static com.zhentao.common.user.UserCommon.CHARGE_USER_LOGIN_KEY_SCHEDULE;
import static com.zhentao.core.ChargeCoreParams.CHARGE_CORE_GUN_STATUS_MAP;

/**
 * @author 31919
 * @description 针对表【charge_station_info】的数据库操作Service实现
 * @createDate 2024-12-22 19:57:12
 */
@Service
public class ChargeStationInfoServiceImpl extends ServiceImpl<ChargeStationInfoMapper, ChargeStationInfo>
        implements ChargeStationInfoService {

    /**
     * 获取充电枪信息
     * WXQ
     */
    @Resource
    ChargeStationGunService chargeStationGunService;
    /**
     * 获取专用充电类型
     * WXQ
     */
    @Resource
    ChargeStationDedicatedService chargeStationDedicatedService;
    /**
     * 获取充电桩评论信息
     * WXQ
     */
    @Resource
    ChargeStationCommentService chargeStationCommentService;
    @Autowired
    private StringRedisTemplate redisTemplate;


    private static final double RADIUS_OF_EARTH = 6371; // 地球半径，单位为公里

    /**
     * 计算两个地理坐标点之间的距离
     *
     * @param lat1 点1的纬度
     * @param lon1 点1的经度
     * @param lat2 点2的纬度
     * @param lon2 点2的经度
     * @return 两点间的距离，单位为公里
     */
    public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        double latDistance = Math.toRadians(lat2 - lat1);
        double lonDistance = Math.toRadians(lon2 - lon1);
        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
                + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
                * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return RADIUS_OF_EARTH * c;
    }

    @Override
    public ResponseResult getCoreList(ChargeStationInfoDto chargeStationInfoDto) {


        LambdaQueryWrapper<ChargeStationInfo> chargeStationInfoLambdaQueryWrapper = Wrappers.<ChargeStationInfo>lambdaQuery();


        System.out.println("纬度" + chargeStationInfoDto.getLatitude() + "" + chargeStationInfoDto.getLongitude());
        chargeStationInfoLambdaQueryWrapper
                .like(StringUtils.checkValNotNull(chargeStationInfoDto.getCoreGetCount()), ChargeStationInfo::getStationName, chargeStationInfoDto.getCoreGetCount());
        chargeStationInfoLambdaQueryWrapper
                .eq(StringUtils.checkValNotNull(chargeStationInfoDto.getParkFee()), ChargeStationInfo::getParkFee, chargeStationInfoDto.getParkFee());
        chargeStationInfoLambdaQueryWrapper
                .eq(StringUtils.checkValNotNull(chargeStationInfoDto.getShoppingMall()), ChargeStationInfo::getShoppingMall, chargeStationInfoDto.getShoppingMall());
        chargeStationInfoLambdaQueryWrapper
                .eq(StringUtils.checkValNotNull(chargeStationInfoDto.getLounge()), ChargeStationInfo::getLounge, chargeStationInfoDto.getLounge());
        chargeStationInfoLambdaQueryWrapper
                .eq(StringUtils.checkValNotNull(chargeStationInfoDto.getToilet()), ChargeStationInfo::getToilet, chargeStationInfoDto.getToilet());
        chargeStationInfoLambdaQueryWrapper
                .eq(StringUtils.checkValNotNull(chargeStationInfoDto.getWashCar()), ChargeStationInfo::getWashCar, chargeStationInfoDto.getWashCar());

        if (chargeStationInfoDto.getHandoff() == 0) {
//            chargeStationInfoLambdaQueryWrapper.orderByDesc()
            // 示例调用

            List<ChargeStationInfo> list = this.list(chargeStationInfoLambdaQueryWrapper);
            List<ChargesStationInfoVo> chargesStationInfoVos = new ArrayList<>();
            for (ChargeStationInfo chargeStationInfo : list) {

                double distance = calculateDistance(
                        chargeStationInfoDto.getLatitude().doubleValue(),
                        chargeStationInfoDto.getLongitude().doubleValue(),
                        chargeStationInfo.getLatitude().doubleValue(),
                        chargeStationInfo.getLongitude().doubleValue()
                );
                distance = Math.round(distance * 10.0) / 10.0;
                System.out.println("距离：" + distance + " 公里");
                List<ChargeStationGun> gunCount = chargeStationGunService.list(Wrappers.<ChargeStationGun>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getId()), ChargeStationGun::getStationId, chargeStationInfo.getId()));
                List<ChargeStationGun> gunCountEnd = chargeStationGunService.list(Wrappers.<ChargeStationGun>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getId()), ChargeStationGun::getStationId, chargeStationInfo.getId()).eq(ChargeStationGun::getStatus, 0));

                long startTime = chargeStationInfo.getBusinessStartTime().getTime();
                long endTime = chargeStationInfo.getBusinessEndTime().getTime();
                String durationInMillis;
                // 计算营业时长（毫秒）
                long l = startTime - endTime;

                if (l == 0) {
                    durationInMillis = "24";
                } else {
                    Date businessStartTime = chargeStationInfo.getBusinessStartTime();
                    int hours1 = businessStartTime.getHours();
                    int minutes = businessStartTime.getMinutes();


                    Date businessEndTime = chargeStationInfo.getBusinessEndTime();
                    int hours2 = businessEndTime.getHours();
                    int minutes2 = businessEndTime.getMinutes();

                    durationInMillis = hours1 + ":" + minutes + "-" + hours2 + ":" + minutes2;
                }

                ChargesStationInfoVo chargesStationInfoVo = new ChargesStationInfoVo();
                BeanUtil.copyProperties(chargeStationInfo, chargesStationInfoVo);
                chargesStationInfoVo.setGunCount(gunCount.size());
                chargesStationInfoVo.setGunCountEnd(gunCountEnd.size());
                chargesStationInfoVo.setOpeningHours(durationInMillis);
                chargesStationInfoVo.setDistance(distance);
                ChargeStationDedicated one = chargeStationDedicatedService.getOne(Wrappers.<ChargeStationDedicated>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getDedicatedType()), ChargeStationDedicated::getId, chargeStationInfo.getDedicatedType()));
                chargesStationInfoVo.setDedicatedName(one.getDedicatedName());
                chargesStationInfoVos.add(chargesStationInfoVo);

            }
            chargesStationInfoVos.sort(Comparator.comparing(ChargesStationInfoVo::getDistance));

            return ResponseResult.okResult(chargesStationInfoVos);
        }


        if (chargeStationInfoDto.getHandoff() == 1) {
            chargeStationInfoLambdaQueryWrapper.orderByAsc(ChargeStationInfo::getPrice);
        }

        /**
         * 根据评论数量进行排序
         */
        if (chargeStationInfoDto.getHandoff() == 2) {

            List<ChargeStationInfo> list = this.list(chargeStationInfoLambdaQueryWrapper);
            List<ChargesStationInfoVo> chargesStationInfoVos = new ArrayList<>();
            for (ChargeStationInfo chargeStationInfo : list) {
                //获取评论条数
                List<ChargeStationComment> pinglu = chargeStationCommentService.list(Wrappers.<ChargeStationComment>lambdaQuery().eq(ChargeStationComment::getStationId, chargeStationInfo.getId()));

                double distance = calculateDistance(
                        chargeStationInfoDto.getLatitude().doubleValue(),
                        chargeStationInfoDto.getLongitude().doubleValue(),
                        chargeStationInfo.getLatitude().doubleValue(),
                        chargeStationInfo.getLongitude().doubleValue()
                );
                distance = Math.round(distance * 10.0) / 10.0;
                System.out.println("距离：" + distance + " 公里");


                List<ChargeStationGun> gunCount = chargeStationGunService.list(Wrappers.<ChargeStationGun>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getId()), ChargeStationGun::getStationId, chargeStationInfo.getId()));
                List<ChargeStationGun> gunCountEnd = chargeStationGunService.list(Wrappers.<ChargeStationGun>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getId()), ChargeStationGun::getStationId, chargeStationInfo.getId()).eq(ChargeStationGun::getStatus, 0));

                long startTime = chargeStationInfo.getBusinessStartTime().getTime();
                long endTime = chargeStationInfo.getBusinessEndTime().getTime();
                String durationInMillis;
                // 计算营业时长（毫秒）
                long l = startTime - endTime;

                if (l == 0) {
                    durationInMillis = "24";
                } else {
                    Date businessStartTime = chargeStationInfo.getBusinessStartTime();
                    int hours1 = businessStartTime.getHours();
                    int minutes = businessStartTime.getMinutes();


                    Date businessEndTime = chargeStationInfo.getBusinessEndTime();
                    int hours2 = businessEndTime.getHours();
                    int minutes2 = businessEndTime.getMinutes();

                    durationInMillis = hours1 + ":" + minutes + "-" + hours2 + ":" + minutes2;
                }


                ChargesStationInfoVo chargesStationInfoVo = new ChargesStationInfoVo();
                BeanUtil.copyProperties(chargeStationInfo, chargesStationInfoVo);
                chargesStationInfoVo.setGunCount(gunCount.size());
                chargesStationInfoVo.setGunCountEnd(gunCountEnd.size());
                chargesStationInfoVo.setOpeningHours(durationInMillis);
                chargesStationInfoVo.setPingluCount(pinglu.size());
                chargesStationInfoVo.setDistance(distance);
                ChargeStationDedicated one = chargeStationDedicatedService.getOne(Wrappers.<ChargeStationDedicated>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getDedicatedType()), ChargeStationDedicated::getId, chargeStationInfo.getDedicatedType()));
                chargesStationInfoVo.setDedicatedName(one.getDedicatedName());
                chargesStationInfoVos.add(chargesStationInfoVo);

            }
            chargesStationInfoVos.sort(Comparator.comparing(ChargesStationInfoVo::getPingluCount).reversed());

            return ResponseResult.okResult(chargesStationInfoVos);
        }

        //根据人气
        if (chargeStationInfoDto.getHandoff() == 3) {

            List<ChargeStationInfo> list = this.list(chargeStationInfoLambdaQueryWrapper);
            List<ChargesStationInfoVo> chargesStationInfoVos = new ArrayList<>();
            for (ChargeStationInfo chargeStationInfo : list) {


                double distance = calculateDistance(
                        chargeStationInfoDto.getLatitude().doubleValue(),
                        chargeStationInfoDto.getLongitude().doubleValue(),
                        chargeStationInfo.getLatitude().doubleValue(),
                        chargeStationInfo.getLongitude().doubleValue()
                );
                distance = Math.round(distance * 10.0) / 10.0;
                System.out.println("距离：" + distance + " 公里");

                //获取评论人数
                List<ChargeStationComment> renshu = chargeStationCommentService.
                        list(Wrappers.<ChargeStationComment>lambdaQuery()
                                .eq(ChargeStationComment::getStationId, chargeStationInfo.getId()));

                // 使用 Stream 去重，假设根据 userId 去重
                List<ChargeStationComment> uniqueRenshu = renshu.stream()
                        .collect(Collectors.collectingAndThen(
                                Collectors.toMap(
                                        ChargeStationComment::getUserId,  // 根据 userId 去重
                                        comment -> comment,
                                        (existing, replacement) -> existing  // 如果有重复，保留第一个
                                ),
                                map -> new ArrayList<>(map.values())
                        ));

                List<ChargeStationGun> gunCount = chargeStationGunService.list(Wrappers.<ChargeStationGun>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getId()), ChargeStationGun::getStationId, chargeStationInfo.getId()));
                List<ChargeStationGun> gunCountEnd = chargeStationGunService.list(Wrappers.<ChargeStationGun>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getId()), ChargeStationGun::getStationId, chargeStationInfo.getId()).eq(ChargeStationGun::getStatus, 0));

                long startTime = chargeStationInfo.getBusinessStartTime().getTime();
                long endTime = chargeStationInfo.getBusinessEndTime().getTime();
                String durationInMillis;
                // 计算营业时长（毫秒）
                long l = startTime - endTime;

                if (l == 0) {
                    durationInMillis = "24";
                } else {
                    Date businessStartTime = chargeStationInfo.getBusinessStartTime();
                    int hours1 = businessStartTime.getHours();
                    int minutes = businessStartTime.getMinutes();


                    Date businessEndTime = chargeStationInfo.getBusinessEndTime();
                    int hours2 = businessEndTime.getHours();
                    int minutes2 = businessEndTime.getMinutes();

                    durationInMillis = hours1 + ":" + minutes + "-" + hours2 + ":" + minutes2;
                }


                ChargesStationInfoVo chargesStationInfoVo = new ChargesStationInfoVo();
                BeanUtil.copyProperties(chargeStationInfo, chargesStationInfoVo);
                chargesStationInfoVo.setGunCount(gunCount.size());
                chargesStationInfoVo.setDistance(distance);
                chargesStationInfoVo.setGunCountEnd(gunCountEnd.size());
                chargesStationInfoVo.setOpeningHours(durationInMillis);
                chargesStationInfoVo.setRenshuCount(uniqueRenshu.size());
                ChargeStationDedicated one = chargeStationDedicatedService.getOne(Wrappers.<ChargeStationDedicated>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getDedicatedType()), ChargeStationDedicated::getId, chargeStationInfo.getDedicatedType()));
                chargesStationInfoVo.setDedicatedName(one.getDedicatedName());
                chargesStationInfoVos.add(chargesStationInfoVo);

            }
            chargesStationInfoVos.sort(Comparator.comparing(ChargesStationInfoVo::getRenshuCount).reversed());

            return ResponseResult.okResult(chargesStationInfoVos);
        }


        List<ChargeStationInfo> list = this.list(chargeStationInfoLambdaQueryWrapper);
        List<ChargesStationInfoVo> chargesStationInfoVos = new ArrayList<>();
        for (ChargeStationInfo chargeStationInfo : list) {
            List<ChargeStationGun> gunCount = chargeStationGunService.list(Wrappers.<ChargeStationGun>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getId()), ChargeStationGun::getStationId, chargeStationInfo.getId()));
            List<ChargeStationGun> gunCountEnd = chargeStationGunService.list(Wrappers.<ChargeStationGun>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getId()), ChargeStationGun::getStationId, chargeStationInfo.getId()).eq(ChargeStationGun::getStatus, 0));


            double distance = calculateDistance(
                    chargeStationInfoDto.getLatitude().doubleValue(),
                    chargeStationInfoDto.getLongitude().doubleValue(),
                    chargeStationInfo.getLatitude().doubleValue(),
                    chargeStationInfo.getLongitude().doubleValue()
            );
            distance = Math.round(distance * 10.0) / 10.0;
            System.out.println("距离：" + distance + " 公里");

            long startTime = chargeStationInfo.getBusinessStartTime().getTime();
            long endTime = chargeStationInfo.getBusinessEndTime().getTime();
            String durationInMillis;
            // 计算营业时长（毫秒）
            long l = startTime - endTime;

            if (l == 0) {
                durationInMillis = "24";
            } else {
                Date businessStartTime = chargeStationInfo.getBusinessStartTime();
                int hours1 = businessStartTime.getHours();
                int minutes = businessStartTime.getMinutes();
                Date businessEndTime = chargeStationInfo.getBusinessEndTime();
                int hours2 = businessEndTime.getHours();
                int minutes2 = businessEndTime.getMinutes();

                durationInMillis = hours1 + ":" + minutes + "-" + hours2 + ":" + minutes2;
            }
            ChargesStationInfoVo chargesStationInfoVo = new ChargesStationInfoVo();
            BeanUtil.copyProperties(chargeStationInfo, chargesStationInfoVo);
            chargesStationInfoVo.setGunCount(gunCount.size());
            chargesStationInfoVo.setGunCountEnd(gunCountEnd.size());
            chargesStationInfoVo.setOpeningHours(durationInMillis);
            chargesStationInfoVo.setDistance(distance);
            ChargeStationDedicated one = chargeStationDedicatedService.getOne(Wrappers.<ChargeStationDedicated>lambdaQuery().eq(StringUtils.checkValNotNull(chargeStationInfo.getDedicatedType()), ChargeStationDedicated::getId, chargeStationInfo.getDedicatedType()));
            chargesStationInfoVo.setDedicatedName(one.getDedicatedName());
            chargesStationInfoVos.add(chargesStationInfoVo);

        }
        return ResponseResult.okResult(chargesStationInfoVos);
    }


    /**
     * 管理端
     *
     * @param chargeStationInfoDto
     * @return WXQ
     */
    @Override
    public PermissionResult GetAdminChangeList(ChargeStationInfoDto chargeStationInfoDto) {
        AdminUserPermissionUtils permissionUtils = new AdminUserPermissionUtils(redisTemplate);
        ResponseResult result = permissionUtils.hasPermission(SYS_SITE_SELECT);
        if (!(result.getCode() == 200000)) {
            return PermissionResult.ERROR(result.getCode(), result.getErrorMessage());
        }

        Page<ChargeStationInfo> chargeStationInfoPage = new Page<>(chargeStationInfoDto.getPageNum(), chargeStationInfoDto.getPageSize());
        LambdaQueryWrapper<ChargeStationInfo> eq = Wrappers.<ChargeStationInfo>lambdaQuery().eq(ChargeStationInfo::getDel, 0);


        Page<ChargeStationInfo> page = this.page(chargeStationInfoPage, eq);

        return PermissionResult.OK(200000, "查询成功", page);
    }

    @Override
    public PermissionResult AdminChangeUpdate(ChargeStationInfoDto chargeStationInfoDto) {
        AdminUserPermissionUtils permissionUtils = new AdminUserPermissionUtils(redisTemplate);
        ResponseResult result = permissionUtils.hasPermission(SYS_SITE_EDIT);
        if (chargeStationInfoDto == null) {
            return PermissionResult.ERROR(400000, "不能为空");
        }
        if (!(result.getCode() == 200000)) {
            return PermissionResult.ERROR(result.getCode(), result.getErrorMessage());
        }
        ChargeStationInfo chargeStationInfo = new ChargeStationInfo();

        BeanUtil.copyProperties(chargeStationInfoDto, chargeStationInfo);
        boolean update = this.updateById(chargeStationInfo);
        if (update) {
            return PermissionResult.OK(200000, "修改成功");
        }
        return PermissionResult.ERROR(400000, "修改失败");
    }

    @Override
    public PermissionResult AdminChangeDel(ChargeStationInfoDto chargeStationInfoDto) {
        AdminUserPermissionUtils permissionUtils = new AdminUserPermissionUtils(redisTemplate);
        ResponseResult result = permissionUtils.hasPermission(SYS_SITE_DEL);
        if (!(result.getCode() == 200000)) {
            return PermissionResult.ERROR(result.getCode(), result.getErrorMessage());
        }
        if (chargeStationInfoDto == null) {
            return PermissionResult.ERROR(400000, "不能为空");
        }
        boolean update = this.update(Wrappers.<ChargeStationInfo>lambdaUpdate().set(ChargeStationInfo::getDel, 1).eq(ChargeStationInfo::getId, chargeStationInfoDto.getId()));
        if (update) {
            return PermissionResult.OK(200000, "删除成功");
        }

        return PermissionResult.ERROR(400000, "删除失败");

    }


    /*
     * @description  我的桩站查询
     * @author 振涛教育_小Q
     * @date    2025/1/5 1:33
     * @param param
     * @return
     */
    @Override
    public ResponseResult myCoreList(ChargeStationInfoParam param) {
        // 获取当前登录用户
        String userId = redisTemplate.opsForValue().get(CHARGE_USER_LOGIN_KEY_SCHEDULE);
        if (StringUtils.checkValNull(userId)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.CHARGE_USER_DATA_NOT_EXIST);
        }
        Page<ChargeStationInfo> page = new Page<>(param.getPageNum(), param.getPageSize());
        this.page(page, Wrappers.<ChargeStationInfo>lambdaQuery()
                .eq(ChargeStationInfo::getUserId, Integer.valueOf(userId))
                .orderByDesc(ChargeStationInfo::getCreateTime));
        List<ChargeStationInfo> records = page.getRecords();
        for (int i = 0; i < records.size(); i++) {
            ChargeStationInfo stationInfo = records.get(i);
            ChargeMyStationInfoVo vo = new ChargeMyStationInfoVo();
            BeanUtils.copyProperties(stationInfo, vo);
            if (stationInfo.getId() != null) {
                List<ChargeStationGun> gunStation = chargeStationGunService.list(Wrappers.<ChargeStationGun>lambdaQuery()
                        .eq(ChargeStationGun::getStationId, stationInfo.getId()));
                if (gunStation != null && gunStation.size() > 0) {
                    vo.setStationGunList(gunStation);
                    for (ChargeStationGun stationGun : gunStation) {
                        stationGun.setStationStatusName(CHARGE_CORE_GUN_STATUS_MAP.get(stationGun.getStatus()));
                    }
                }
                if (stationInfo.getDedicatedType() != null) {
                    ChargeStationDedicated dedicated = chargeStationDedicatedService.getById(stationInfo.getDedicatedType());
                    if (dedicated != null) {
                        vo.setDedicatedTypeName(dedicated.getDedicatedName());
                    }
                }
            }
            records.set(i, vo);
        }
        return ResponseResult.okResult(page);
    }


}




